from typing import Optional, Dict, Any
from utils.constants import ErrorCode  # 对接全局错误码

# ===================== 基础异常类（所有自定义异常的父类） =====================
class MaessBaseException(Exception):
    """项目基础异常类，包含错误码、错误信息、上下文"""
    def __init__(
        self,
        error_code: ErrorCode = ErrorCode.SYSTEM_ERROR,
        message: Optional[str] = None,
        context: Optional[Dict[str, Any]] = None
    ):
        self.error_code = error_code
        self.message = message or error_code.name  # 默认用错误码名称作为消息
        self.context = context or {}  # 额外上下文（如task_id、agent_name）
        super().__init__(self.message)

    def __str__(self):
        """格式化异常输出：包含错误码、消息、上下文"""
        context_str = ", ".join([f"{k}={v}" for k, v in self.context.items()])
        return f"[{self.error_code.value}] {self.message} (context: {context_str})"

# ===================== 业务异常类（按模块分类） =====================
class RedisError(MaessBaseException):
    """Redis操作异常"""
    def __init__(self, message: Optional[str] = None, context: Optional[Dict[str, Any]] = None):
        super().__init__(
            error_code=ErrorCode.REDIS_ERROR,
            message=message or "Redis operation failed",
            context=context
        )


# 兼容旧导入名称
RedisConnectionError = RedisError
RedisOperationError  = RedisError

class NacosError(MaessBaseException):
    """Nacos操作异常"""
    def __init__(self, message: Optional[str] = None, context: Optional[Dict[str, Any]] = None):
        super().__init__(
            error_code=ErrorCode.NACOS_ERROR,
            message=message or "Nacos operation failed",
            context=context
        )

class AgentCallError(MaessBaseException):
    """Agent调用异常"""
    def __init__(self, message: Optional[str] = None, context: Optional[Dict[str, Any]] = None):
        super().__init__(
            error_code=ErrorCode.AGENT_CALL_ERROR,
            message=message or "Agent call failed",
            context=context
        )


class WorkflowError(MaessBaseException):
    """工作流异常"""
    def __init__(self, message: Optional[str] = None, context: Optional[Dict[str, Any]] = None):
        super().__init__(
            error_code=ErrorCode.SYSTEM_ERROR,  # 可以根据实际情况选择更合适的错误码
            message=message or "Workflow execution failed",
            context=context
        )


class ToolError(MaessBaseException):
    """工具调用异常"""
    def __init__(self, message: Optional[str] = None, context: Optional[Dict[str, Any]] = None):
        super().__init__(
            error_code=ErrorCode.AGENT_CALL_ERROR,
            message=message or "Agent call failed",
            context=context
        )

class LockAcquireError(MaessBaseException):
    """分布式锁获取异常"""
    def __init__(self, message: Optional[str] = None, context: Optional[Dict[str, Any]] = None):
        super().__init__(
            error_code=ErrorCode.LOCK_ACQUIRE_ERROR,
            message=message or "Distributed lock acquire failed",
            context=context
        )

class RateLimitError(MaessBaseException):
    """限流触发异常"""
    def __init__(self, message: Optional[str] = None, context: Optional[Dict[str, Any]] = None):
        super().__init__(
            error_code=ErrorCode.RATE_LIMIT_ERROR,
            message=message or "Rate limit triggered",
            context=context
        )

class ComplianceError(MaessBaseException):
    """合规校验异常"""
    def __init__(self, message: Optional[str] = None, context: Optional[Dict[str, Any]] = None):
        super().__init__(
            error_code=ErrorCode.COMPLIANCE_ERROR,
            message=message or "Compliance check failed",
            context=context
        )

class ParamError(MaessBaseException):
    """参数错误异常"""
    def __init__(self, message: Optional[str] = None, context: Optional[Dict[str, Any]] = None):
        super().__init__(
            error_code=ErrorCode.PARAM_ERROR,
            message=message or "Invalid parameter",
            context=context
        )

class AgentNotFoundError(MaessBaseException):
    """未找到健康Agent实例异常"""
    def __init__(self, message: str, context: Optional[Dict[str, Any]] = None):
        super().__init__(
            error_code=ErrorCode.AGENT_NOT_FOUND_ERROR,  # 建议在ErrorCode中新增该枚举值
            message=message,
            context=context
        )

# 兼容旧导入名称
AgentError = AgentCallError

# ===================== 新增：工具操作异常 =====================
class CircuitBreakerOpenError(MaessBaseException):
    """熔断器开启异常"""
    def __init__(self, message: Optional[str] = None, context: Optional[Dict[str, Any]] = None):
        super().__init__(
            error_code=ErrorCode.CIRCUIT_BREAKER_OPEN,
            message=message or "Circuit breaker is open",
            context=context
        )

class ToolError(MaessBaseException):
    """工具操作异常（适用于text_processing、text_qa/tools等工具模块）"""
    def __init__(self, message: Optional[str] = None, context: Optional[Dict[str, Any]] = None):
        super().__init__(
            error_code=ErrorCode.TOOL_ERROR,  # 需在 utils/constants.py 的 ErrorCode 中新增 TOOL_ERROR 枚举
            message=message or "Tool operation failed",
            context=context
        )

class ModelError(MaessBaseException):
    """模型操作异常（适用于模型客户端相关错误）"""
    def __init__(self, message: Optional[str] = None, context: Optional[Dict[str, Any]] = None):
        super().__init__(
            error_code=ErrorCode.MODEL_ERROR,  # 需在 utils/constants.py 的 ErrorCode 中新增 MODEL_ERROR 枚举
            message=message or "Model operation failed",
            context=context
        )

# ===================== 使用示例 =====================
if __name__ == "__main__":
    try:
        # 模拟Redis操作失败
        raise RedisError(
            message="Redis HSETALL failed",
            context={"key": "task:state:task_123", "error": "connection timeout"}
        )
    except MaessBaseException as e:
        print(f"捕获异常：{e}")
        print(f"错误码：{e.error_code.value}")
        print(f"上下文：{e.context}")

    try:
        # 模拟Agent调用失败
        raise AgentCallError(
            message="TextQAAgent execute timeout",
            context={"task_id": "task_123", "agent_name": "text_qa_agent", "timeout": 10}
        )
    except MaessBaseException as e:
        print(f"\n捕获异常：{e}")

    # 新增：模拟工具操作失败（ToolError使用示例）
    try:
        raise ToolError(
            message="Text embedding generation failed",
            context={"tool_name": "text_processing", "text": "测试文本", "error": "model not loaded"}
        )
    except MaessBaseException as e:
        print(f"\n捕获ToolError：{e}")
        print(f"错误码：{e.error_code.value}")
        print(f"上下文：{e.context}")